package cn.edu.dlmu.cogo.framework.context;

import cn.hutool.core.lang.Console;
import cn.hutool.core.util.ReflectUtil;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author yixi
 */
public class ContextContainer implements ApplicationContext{

    private static final ApplicationContext APPLICATION_CONTEXT = new ContextContainer();

    private final Map<String, Class<?>> NAME_MAP;

    private final Map<Class<?>, Object> BEAN_MAP;

    private ContextContainer(){
        this.NAME_MAP = new HashMap<>();
        this.BEAN_MAP = new HashMap<>();
    }

    public static ApplicationContext getApplicationContext(){
        return APPLICATION_CONTEXT;
    }

    @Override
    public boolean containsBean(String beanName) {
        return NAME_MAP.containsKey(beanName) && BEAN_MAP.containsKey(NAME_MAP.get(beanName));
    }

    @Override
    public boolean containsBean(Class<?> beanClass) {
        return BEAN_MAP.containsKey(beanClass);
    }

    @Override
    public boolean containsBean(Object bean) {
        return BEAN_MAP.containsKey(bean.getClass());
    }

    @Override
    public Set<String> getNames() {
        return NAME_MAP.keySet();
    }

    @Override
    public Set<Class<?>> getClasses() {
        return BEAN_MAP.keySet();
    }

    @Override
    public Object getBean(Class<?> beanClass) {
        return BEAN_MAP.get(beanClass);
    }

    @Override
    public Object getBean(String beanName) {
        return BEAN_MAP.get(NAME_MAP.get(beanName));
    }

    @Override
    public void setBean(Object bean) {
        BEAN_MAP.put(bean.getClass(), bean);
        NAME_MAP.put(formatName(bean.getClass().getSimpleName()), bean.getClass());
        showSetBeanInfo(formatName(bean.getClass().getSimpleName()), bean.getClass().getName());
    }

    @Override
    public void setBean(Class<?> beanClass) {
        BEAN_MAP.put(beanClass, ReflectUtil.newInstance(beanClass));
        NAME_MAP.put(formatName(beanClass.getSimpleName()), beanClass);
        showSetBeanInfo(formatName(beanClass.getSimpleName()), beanClass.getName());
    }

    @Override
    public void setBean(Object bean, String beanName) {
        if ("".equals(beanName)){
            setBean(bean);
            return;
        }
        BEAN_MAP.put(bean.getClass(), bean);
        NAME_MAP.put(formatName(beanName), bean.getClass());
        showSetBeanInfo(formatName(beanName), bean.getClass().getName());
    }

    @Override
    public void setBean(Class<?> beanClass, String beanName) {
        if ("".equals(beanName)){
            setBean(beanClass);
            return;
        }
        BEAN_MAP.put(beanClass, ReflectUtil.newInstance(beanClass));
        NAME_MAP.put(formatName(beanName), beanClass);
        showSetBeanInfo(formatName(beanName), beanClass.getName());
    }

    @Override
    public void removeBean(Class<?> beanClass) {
        Object remove = BEAN_MAP.remove(beanClass);
        NAME_MAP.remove(formatName(beanClass.getSimpleName()));
        if (remove != null){
            Console.log("{} [Cogo容器]Bean对象移除成功[{}]",Environment.getSystemTime(), beanClass.getName());
        }
    }

    private String formatName(String beanName) {
        if (Character.isLowerCase(beanName.charAt(0))) {
            return beanName;
        } else {
            return Character.toLowerCase(beanName.charAt(0)) + beanName.substring(1);
        }
    }

    private void showSetBeanInfo(String beanName,String className){
        Console.log("{} [Cogo容器]Bean对象设置成功[{}][{}]",Environment.getSystemTime(),className,beanName);
    }
}
